from intstr import IntStr
import string

redis_keyer = IntStr(
    string.ascii_uppercase + string.ascii_lowercase + string.digits
)

REDIS_KEY_SEQ = '.RedisKeySeq'
REDIS_KEY = '.RedisKey'
REDIS_ID_KEY = '.RedisIdKey'

_EXIST = set()


class RedisKey(object):
    def __delitem__(self, key):
        redis = self.__redis
        id = redis.hget(REDIS_KEY, key)
        if not id:
            return
        p = redis.pipeline()
        p.hdel(REDIS_ID_KEY, id)
        p.hdel(REDIS_KEY, key)
        p.execute()

    def __init__(self, redis):
        self.__redis = redis

    def __getattr__(self, attr):
        return lambda name: self(attr, name)

    def __call__(self, key, name=''):
        redis = self.__redis
        if key in _EXIST:
            raise Exception('REDIS KEY DEFINED %s' % key)
        _EXIST.add(key)
        _key = redis.hget(REDIS_KEY, key)
        if _key is None:
            id = redis.incr(REDIS_KEY_SEQ)
            _id = redis_keyer.encode(id)
            if name and '%' in name:
                _id = _id + "#" + name
            with redis.pipeline() as p:
                p.hset(REDIS_KEY, key, _id)
                p.hset(REDIS_ID_KEY, _id, key)
                p.execute()
        return _key

    def __iter__(self):
        return iter(self.__redis.hgetall(REDIS_KEY).items())


class RedisKeyEncode:
    def __init__(self):
        self.__o = {}

    def __call__(self, key, val):
        o = self.__o
        li = key.split('.')
        last = li.pop()
        for i in li:
            if i in o:
                o = o[i]
            else:
                o[i] = o = {}
        o[last] = val

    def items(self):
        return self.__o.items()

    def to_cls(self, o=None, indent=0):
        if o is None:
            o = self.__o
        li = []
        tab = '    ' * indent
        for k, v in o.items():
            if isinstance(v, dict):
                if 1 == indent:
                    li.append('')
                li.append(tab + f"class {k}:")
                li.append(self.to_cls(v, indent + 1))
            else:
                li.append(tab + f'{k} = "{v}"')
            if not indent:
                li.append('\n')
        return '\n'.join(li)
